package com.springboot.lock.lock_redis.lock;

import com.springboot.lock.config.RedisClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Random;

/**
 * @Author: TongRui乀
 * @Date: 2020-08-06 9:35
 * @description：
 */
@Slf4j
@Service
public class RedisDistributeLock implements DistributeLock {

    @Autowired
    private RedisClient redisClient;
    // 用于存储当前线程获取到锁的 唯一标识 这里是 value值
    private ThreadLocal<String> threadFlag = new ThreadLocal<>();

    @Override
    public boolean tryLock(String key, String value, Integer expire) {

        // set 成功返回OK 失败 返回 null
        String flag = this.redisClient.set(key, value, "NX", "PX", expire);

        if(flag == null){
            // 没有获取到货 判断是否是重入锁
            String oldValue = this.redisClient.get(key);

            if(oldValue != null && oldValue.equals(threadFlag.get())){
                log.info("获取重入锁：{}", Thread.currentThread().getName());
                // 设置超时时间
                redisClient.expire(key, expire);
                return true;
            }else {
                return false;
            }
        }
        // 将线程标识放入
        threadFlag.set(value);
        return true;
    }

    @Override
    public boolean tryLock(String key, String value, Integer expire, long retryMills) {
        // set 成功返回OK 失败 返回 null
        String flag = this.redisClient.set(key, value, "NX", "PX", expire);

        if(flag == null){
            // 没有获取到货 判断是否是重入锁
            String oldValue = this.redisClient.get(key);
            if(oldValue != null && oldValue.equals(threadFlag.get())){
                // 设置超时时间
                redisClient.expire(key, expire);
                return true;
            }else {
                // 循环获取
                if(retryMills > 0){
                    long target = System.currentTimeMillis() + retryMills;
                    while (System.currentTimeMillis() < target){
                        if(this.redisClient.set(key, value, "NX", "PX", expire) != null){
                            // 将线程标识放入
                            threadFlag.set(value);
                            return true;
                        }
                        try {
                            Random random = new Random();
                            Thread.sleep(100 + random.nextInt(100));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                return false;
            }
        }
        // 将线程标识放入
        threadFlag.set(value);
        return true;
    }

    @Override
    public void unLock(String key) {

        String value = this.redisClient.get(key);

        if(!StringUtils.isEmpty(value)){
            this.redisClient.delete(key);
        }
        // 清空ThreadLocal
        threadFlag.remove();

        log.info("释放锁：{}", Thread.currentThread().getName());

    }
}
